#include "Font.h"

// Optionally disable fonts (to remove freetype dependency)
#if BUZZ_USE_FONTS == 1

#include <stdio.h>
#include <vector>
#include <string>

Font::Font(char* filename, int height) {
	textures = new GLuint[128];
	this->height = height;

	//printf("Loading font %s\n", filename);

	FT_Library library;
	if (FT_Init_FreeType(&library)) {
		printf("Error initializing FreeType\n");
		return;
	}

	FT_Face face;

	if (FT_New_Face(library, filename, 0, &face)) {
		printf("Error building font face for font %s\n", filename);
		return;
	}

	FT_Set_Char_Size(face, height << 6, height << 6, 96, 96);

	listBase = glGenLists(128);
	glGenTextures(128, textures);

	for(unsigned char i=0;i<128;i++)
		generateCharacter(face, i);

	FT_Done_Face(face);
	FT_Done_FreeType(library);

	//printf("Loaded font %s\n", filename);
}

Font::~Font() {
	glDeleteLists(listBase, 128);
	glDeleteTextures(128, textures);
	delete [] textures;
}

void Font::renderString(int posX, int posY, const char* text, ...) {
	char ftext[256];
	memset(ftext, 0, sizeof(ftext));
	va_list	ap;

	if (text == NULL) {
		*ftext = 0;
	} else {
		va_start(ap, text);
		vsprintf(ftext, text, ap);
		va_end(ap);
	}

	std::vector<std::string> lines;
	char buffer[128];
	memset(buffer, 0, sizeof(buffer));
	int bufPos = 0;
	for(unsigned int i=0; i<sizeof(ftext); i++) {
		if(ftext[i] == '\n' || ftext[i] == 0) {
			lines.push_back(buffer);
			if(ftext[i] == 0) {
				break;
			} else {
				memset(buffer, 0, sizeof(buffer));
				bufPos = 0;
			}
		} else {
			buffer[bufPos] = ftext[i];
			bufPos++;
		}
	}
	glLoadIdentity();

	int lineNum = 0;
	for(std::vector<std::string>::iterator i = lines.begin(); i != lines.end(); i++) {
		glPushMatrix();
		glTranslatef((float)posX, (float)posY + lineNum*(this->height+3), 0.0f);
		glRotatef(180.0f, (float)posX + 1.0f, 0.0f, 0.0f);
		glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
		glListBase(listBase);
		glCallLists((GLsizei) strlen((*i).c_str()), GL_UNSIGNED_BYTE, (*i).c_str());
		glPopAttrib();
		glPopMatrix();
		lineNum++;
	}
}

void Font::generateCharacter(FT_Face face, char c) {
	if(FT_Load_Glyph(face, FT_Get_Char_Index(face, c), FT_LOAD_DEFAULT)) {
		printf("Loading glyph for character %c\n", c);
		return;
	}

	FT_Glyph glyph;
	if(FT_Get_Glyph(face->glyph, &glyph)){
		printf("Error getting glyph for character %c\n", c);
		return;
	}

	FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);
	FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

	FT_Bitmap& bitmap = bitmap_glyph->bitmap;

	int width = power_of_two(bitmap.width);
	int height = power_of_two(bitmap.rows);

	GLubyte* expandedData = new GLubyte[2 * width * height];

	for(int j=0; j <height;j++) {
		for(int i=0; i < width; i++){
			expandedData[2*(i+j*width)]= expandedData[2*(i+j*width)+1] =
				(i>=bitmap.width || j>=bitmap.rows) ?
				0 : bitmap.buffer[i + bitmap.width*j];
		}
	}

	glBindTexture(GL_TEXTURE_2D, textures[c]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
		GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expandedData );

	delete [] expandedData;

	glNewList(listBase+c, GL_COMPILE);
	glBindTexture(GL_TEXTURE_2D, textures[c]);
	glPushMatrix();

	glTranslatef((float) bitmap_glyph->left,0,0);
	glTranslatef(0,(float) bitmap_glyph->top-bitmap.rows,0);

	float x = (float)bitmap.width / (float)width;
	float y = (float)bitmap.rows / (float)height;

	glBegin(GL_QUADS);
		glTexCoord2d(0,0); glVertex2f(0, (float) bitmap.rows);
		glTexCoord2d(0,y); glVertex2f(0, 0);
		glTexCoord2d(x,y); glVertex2f((float) bitmap.width, 0);
		glTexCoord2d(x,0); glVertex2f((float) bitmap.width, (float) bitmap.rows);
	glEnd();
	glPopMatrix();
	glTranslatef((float) (face->glyph->advance.x >> 6), 0, 0);

	glEndList();
}

#endif //BUZZ_USE_FONTS = 1
